#include "bsp.h"
#include "m26.h"
#include "led.h"
#include "msg_queue.h"
#include "iot.h"
#include "string_util.h"
#include "timer_util.h"

#define MyDebugln(format,...) printf(format"\r\n",##__VA_ARGS__)


#define M26_REBOOT_TIMEOUT_SPAN         10000


Msg  atMsgQueue[20];
Msg  timMsgQueue[20];
MsgQueue ATMsgQueue;



#define TIM_ID_REPORT   0x01
#define TIM_ID_M26_REBOOT   0x02


#define Stage_Pend_RDY  		0
#define Stage_Pend_Pin_RDY      1
#define Stage_Pend_Config       2
#define Stage_Pend_GSM          3
#define Stage_Pend_GPRS         4
#define Stage_Pend_IP           5
#define Stage_Pend_Reg          6
#define Stage_Pend_Reg_SendOK   7
#define Stage_Pend_Reg_Correct  8
#define Stage_Pend_Report       9
#define Stage_Pend_Report_SendOK  10
#define Stage_Pend_Report_Correct 11



int Stage  = Stage_Pend_RDY;



void ReportCallback(uint16_t id)
{
	static uint32_t  device_attr_val  = 0;
LED_On(LED2);	
	MyDebugln("Time to report");
	
	if(Stage >= Stage_Pend_Report){
		Iot_UploadDeviceIntAttribute("akf001", "upload", device_attr_val);
		device_attr_val  += 100;
		
		if(device_attr_val  > 5000){
			device_attr_val  = 0;
		}
		
		
		Stage  = Stage_Pend_Report_SendOK;
	}

	RestartTimer(id, 10000 /TIMER_TICK_PERIOD);
LED_Off(LED2);
}



void TimeoutCallback(uint16_t id)
{
	switch(id)
	{
		case TIM_ID_M26_REBOOT:
			MyDebugln("M26 will reboot...");
			Stage  = Stage_Pend_RDY;
			DestroyTimer(TIM_ID_M26_REBOOT);
			M26_Reboot();  
			break;
		
		default:
			break;
	}
}




void OnRdy(char* str)
{
	sendAtCmd("AT+QIHEAD=1");
	sendAtCmd("AT+QIPROMPT=0");
	Stage  = Stage_Pend_Pin_RDY;
}



void OnPinReady(char* str)
{
	sendAtCmd("AT+CGREG=1");
	Stage  =Stage_Pend_GSM;
}



void OnGsmStateChanged(char* str)
{
	int n, s;
	AT_Echo r;
	r  = ParseGSMStatus(str, &n, &s);
	if(r == AT_No_Error){
		MyDebugln("Parse gsm:%d,%d", n, s);
		if(s == 1  ||  s == 5){
			Stage  = Stage_Pend_GPRS;				
			DestroyTimer(TIM_ID_M26_REBOOT);
			sendAtCmd("AT+CGREG=1");			
		}	
		else{
			if(Stage > Stage_Pend_GSM){
				MyDebugln("Let's pend gsm");
				Stage  = Stage_Pend_GSM;
				
			}
			
			// Gsm OK 超时，则重启
			CreateTimer(TIM_ID_M26_REBOOT, M26_REBOOT_TIMEOUT_SPAN /TIMER_TICK_PERIOD, TimeoutCallback);
		}
	}
	else{
		MyDebugln("Parse gsm error:%d", r);
		sendAtCmd("AT+CREG?");
	}
}



void OnGprsStateChanged(char* str)
{
	static uint8_t GsmErrorCnt  = 0;
	int n, s;
	AT_Echo r;
	r  = ParseGPRSStatus(str, &n, &s);
	if(r == AT_No_Error){
		MyDebugln("Parse gprs:%d,%d", n, s);
		if(s == 1  ||  s == 5){
			Stage  = Stage_Pend_IP;	
			DestroyTimer(TIM_ID_M26_REBOOT);			
			sendAtCmd("AT+QIOPEN=\"UDP\",\"112.80.5.117\",\"5683\"");
		}
		else{
			if(Stage > Stage_Pend_GPRS){	
				MyDebugln("Let's pend gprs");			
				Stage  = Stage_Pend_GPRS;
				
			}		
			// Gprs OK 超时，则重启
			CreateTimer(TIM_ID_M26_REBOOT, M26_REBOOT_TIMEOUT_SPAN /TIMER_TICK_PERIOD, TimeoutCallback);
		}		
	}
	else{
		MyDebugln("Parse gsm error:%d", r);
		sendAtCmd("AT+CGREG?");
	}
}




void OnTcpIpConnected(char* str)
{
	Stage  = Stage_Pend_Reg_SendOK;
	Iot_Register();
}



void OnIotRegistering(char* str)
{
	Stage  = Stage_Pend_Reg_Correct;
}



void OnIotRegistered(char* str)
{	
	Stage  = Stage_Pend_Report;
	CreateTimer(TIM_ID_REPORT, 10000 /TIMER_TICK_PERIOD, ReportCallback);
}



void OnIotReported(char* str)
{
	int length;
	if( sscanf(str, "IPD%d", &length) == 1){
		MyDebugln("Rec %d", length);
	}
}



void OnIotReportError()
{
	Stage  = Stage_Pend_GSM;
	sendAtCmd("AT+CREG?");
}



void ProcessAtMessgae(Msg* pMsg)
{
	
	if(pMsg->type == MSG_AT){
		char* str  = (char*)pMsg->param;		
		
		MyDebugln("%s", str);	
		if(strBeginWith(str, "+CREG")){
			OnGsmStateChanged(str);
		}
		else if(strBeginWith(str, "+CGREG")){
			OnGprsStateChanged(str);
		}
		
		else{
			switch(Stage)
			{
				case Stage_Pend_RDY:
					if( strBeginWith(str, "RDY") ){
						OnRdy(str);
					}
					break;
					
				case Stage_Pend_Pin_RDY:
					if(strBeginWith(str, "+CPIN: READY")){
						OnPinReady(str);
					}
					break;
					
				case Stage_Pend_GSM:
					if( strBeginWith(str, "+CREG") ){
						OnGsmStateChanged(str);
					}
					break;
					
				case Stage_Pend_GPRS:
					if( strBeginWith(str, "+CGREG") ){
						OnGprsStateChanged(str);
					}
					break;
					
				case Stage_Pend_IP:
					if( strBeginWith( str, "8" ) ){
						OnTcpIpConnected(str);
					}
					break;
					
				case Stage_Pend_Reg_SendOK:
					if( strBeginWith( str, "SEND OK") ){
						OnIotRegistering(str);
					}				
					break;
					
				case Stage_Pend_Reg_Correct:
					if( strBeginWith( str, "IPD") ){
						OnIotRegistered(str);
					}
					break;
				
				case Stage_Pend_Report_SendOK:
					if(strBeginWith(str, "SEND OK")){
						Stage  = Stage_Pend_Report_Correct;
					}
					break;
					
				case Stage_Pend_Report_Correct:
					if(strBeginWith(str, "IPD")){
						OnIotReported(str);
					}
					else{
						MyDebugln("Pend report correct error");
						OnIotReportError();
					}
					break;
					
				case Stage_Pend_Report:	
					if( strBeginWith(str, "IPD") ){
						MyDebugln("Report ack");
					}
					break;
			}			
		}

		
	}
}




int main()
{
	int cnt  = 0;
	Msg msg;
	
	Iot_SetAccount("akf001", "0000114");
	
	CreateMessageQueue(&ATMsgQueue, atMsgQueue, 20);	
	
	initBsp();
	LED_Init();
	
	delayMs(1000);
	
	M26_InitPort();
	
	M26_EnablePower();
	delayMs(8000);
	M26_Boot();	
	
	
	
	while(1)
	{
		while( PeekMessage(&ATMsgQueue, &msg))
		{
			if(msg.type  ==  MSG_AT){
				ProcessAtMessgae(&msg);
			}
			else if(msg.type == MSG_TIMER){
				
			}
		}
		
		delayMs(TIMER_TICK_PERIOD);
		
		OnTimerTick();		
	}
	
	
	
	return 0;
}



